from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import pandas as pd
import os
import ddddocr
import time
import json

class Config:
    def __init__(self, config_file='config.json'):
        with open(config_file, 'r', encoding='utf-8') as f:
            self.config = json.load(f)
            
    def update_config(self, new_config):
        self.config.update(new_config)
        with open('config.json', 'w', encoding='utf-8') as f:
            json.dump(self.config, f, ensure_ascii=False, indent=4)
            
    @property
    def url(self):
        return self.config['url']
        
    @property
    def selectors(self):
        return self.config['selectors']
        
    @property
    def excel_columns(self):
        return self.config['excel_columns']

def solve_captcha(driver, ocr):
    try:
        img_element = WebDriverWait(driver, 1).until(
            EC.presence_of_element_located((By.CLASS_NAME, "imgCode"))
        )
        img_element.click()
        time.sleep(0.2)
        img_element.screenshot('captcha.png')
        with open('captcha.png', 'rb') as f:
            return ocr.classification(f.read())
    except Exception as e:
        return None

def try_captcha_and_sms(driver, ocr, max_retries=3):
    for attempt in range(max_retries):
        try:
            captcha_text = solve_captcha(driver, ocr)
            if not captcha_text or len(captcha_text) < 4:
                print(f"第{attempt + 1}次验证码识别无效，重试...")
                continue
                
            driver.execute_script("""
                const input = document.getElementById('certCode');
                input.value = arguments[0];
                input.dispatchEvent(new Event('input', { bubbles: true }));
                input.dispatchEvent(new Event('change', { bubbles: true }));
            """, captcha_text)
            
            get_sms_btn = WebDriverWait(driver, 1).until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, "a.button-cert.button-sms"))
            )
            get_sms_btn.click()
            
            time.sleep(0.2)
            
            try:
                # 等待错误提示框出现
                error_element = WebDriverWait(driver, 2).until(
                    EC.presence_of_element_located((By.XPATH, "//div[contains(@class, 'dialog')]//div[contains(@class, 'content')]"))
                )
                error_text = error_element.text
                confirm_btn = driver.find_element(By.XPATH, "//button[contains(text(), '确定')]")
                
                if "图形验证码输入错误" in error_text:
                    confirm_btn.click()
                    time.sleep(0.2)
                    
                    # 重新获取和点击验证码图片
                    img_element = driver.find_element(By.CLASS_NAME, "imgCode")
                    img_element.click()
                    time.sleep(0.5)  # 等待新验证码加载
                    
                    # 清空验证码输入框
                    driver.execute_script("document.getElementById('certCode').value = '';")
                    print(f"第{attempt + 1}次验证码错误，正在重试...")
                    continue
                    
                elif "当前时间不能发送短信验证码" in error_text:
                    confirm_btn.click()
                    print("当前时间不能发送短信验证码")
                    return False
                
            except:
                print("验证码输入正确！")
                return True
                
        except Exception as e:
            print(f"第{attempt + 1}次尝试出错: {str(e)}")
            if attempt < max_retries - 1:
                print("正在重试...")
                continue
            
    print(f"达到最大重试次数({max_retries}次)，验证码处理失败")
    return False

def run_automation(excel_path, status_callback=None, config_file='config.json'):
    try:
        # 加载配置
        config = Config(config_file)
        
        # 读取Excel文件
        df = pd.read_excel(excel_path, engine='openpyxl')
        if status_callback:
            status_callback(f"成功读取到{len(df)}条记录")
        
        # 初始化 OCR 对象
        ocr = ddddocr.DdddOcr(show_ad=False)
        
        # 初始化浏览器
        options = webdriver.EdgeOptions()
        options.add_argument('--disable-gpu')
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-dev-shm-usage')
        options.page_load_strategy = 'eager'
        driver = webdriver.Edge(options=options)
        driver.implicitly_wait(1)

        try:
            # 预先打开所有标签页
            for _ in range(len(df)):
                driver.execute_script("window.open('about:blank')")
            
            # 第一轮：快速填写所有用户的基本信息
            for index, row in df.iterrows():
                if status_callback:
                    status_callback(f"正在填写第{index+1}个用户的基本信息...")
                driver.switch_to.window(driver.window_handles[index + 1])
                driver.get(config.url)
                
                # 使用配置中的选择器
                driver.execute_script("""
                    function setInputValue(selector, value) {
                        const input = document.querySelector(selector);
                        input.value = value;
                        input.dispatchEvent(new Event('input', { bubbles: true }));
                        input.dispatchEvent(new Event('change', { bubbles: true }));
                    }
                    setInputValue(arguments[0], arguments[4]);
                    setInputValue(arguments[1], arguments[5]);
                    setInputValue(arguments[2], arguments[6]);
                    setInputValue(arguments[3], arguments[7]);
                """, 
                config.selectors['name'],
                config.selectors['idCard'],
                config.selectors['mobile'],
                config.selectors['amount'],
                row[config.excel_columns['name']],
                row[config.excel_columns['idCard']],
                row[config.excel_columns['mobile']],
                row[config.excel_columns['amount']]
                )
            
            # 第二轮：处理验证码
            for index in range(len(df)):
                if status_callback:
                    status_callback(f"正在处理第{index+1}个用户的验证码...")
                driver.switch_to.window(driver.window_handles[index + 1])
                if try_captcha_and_sms(driver, ocr):
                    if status_callback:
                        status_callback(f"第{index+1}个用户处理成功")
                else:
                    if status_callback:
                        status_callback(f"第{index+1}个用户处理失败")
                    
            if status_callback:
                status_callback("\n自动填写完成！浏览器将保持打开状态，请继续填写其他信息。")
                status_callback("完成所有操作后请手动关闭浏览器。")
            
            # 不自动关闭浏览器，返回driver对象
            return driver
                    
        except Exception as e:
            if status_callback:
                status_callback(f"程序执行出错: {str(e)}")
            raise e
            
    except Exception as e:
        if status_callback:
            status_callback(f"发生错误: {str(e)}")
        raise e

def update_config(new_config):
    """更新配置文件"""
    config = Config()
    config.update_config(new_config)
    return True

def get_config():
    """获取当前配置"""
    config = Config()
    return config.config
